package com.lingyuan.product.service.impl;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.alibaba.excel.write.style.column.LongestMatchColumnWidthStyleStrategy;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.lingyuan.common.core.domain.vo.pms.ProductSkuVo;
import com.lingyuan.common.core.exception.ServiceException;
import com.lingyuan.common.core.utils.bean.BeanUtils;
import com.lingyuan.product.config.ExcelConstants;
import com.lingyuan.product.config.ThreadPoolConfig;
import com.lingyuan.product.domain.SkuEntity;
import com.lingyuan.product.domain.SkuImageEntity;
import com.lingyuan.product.domain.SpuAttrValueEntity;
import com.lingyuan.product.domain.SpuDescEntity;
import com.lingyuan.product.domain.vo.AttrVos;
import com.lingyuan.product.domain.vo.ItemVo;
import com.lingyuan.product.mapper.SkuMapper;
import com.lingyuan.product.mapper.SkuSaleAttrValueMapper;
import com.lingyuan.product.service.*;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.OutputStream;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.stream.Collectors;

import static com.lingyuan.product.config.ExcelConstants.PER_SHEET_ROW_COUNT;
import static com.lingyuan.product.config.ExcelConstants.PER_WRITE_ROW_COUNT;

/**
 * @ClassName SkuServiceImpl
 * @Description 描述
 * @Author guoxin
 * @Date 2024/9/18 19:21
 */
@Service
public class SkuServiceImpl extends ServiceImpl<SkuMapper,SkuEntity> implements SkuService {
    @Autowired
    private SkuImageService skuImageService;
    @Autowired
    private SpuDescServcie spuDescServcie;
    @Autowired
    private SpuAttrService spuAttrService;
    @Autowired
    private SkuSaleAttrValueMapper skuSaleAttrValueMapper;
    @Autowired
    private SkuMapper skuMapper;
    @Autowired
    private ThreadPoolConfig threadPoolConfig;
    /**
     * 购物车 拿到商品信息
     */
    @Override
    public ProductSkuVo findBySkuId(Long skuId) {
        //根据id 查询出商品信息
        SkuEntity skuEntity = this.getById(skuId);
        //拿到 商品销售属性
        if (skuEntity == null){
            throw new ServiceException("商品不存在");
        }
        ProductSkuVo productSkuVo = new ProductSkuVo();
        BeanUtils.copyProperties(skuEntity,productSkuVo);
        List<ProductSkuVo.Attr> attrList = skuSaleAttrValueMapper.findById(skuId).stream().map(attr -> {
            ProductSkuVo.Attr attrVo = new ProductSkuVo.Attr();
            BeanUtils.copyProperties(attr, attrVo);
            return attrVo;
        }).collect(Collectors.toList());
        productSkuVo.setAttrs(attrList);
        return productSkuVo;
    }

    /**
     * 添加sku信息
     * @param skuEntity
     */
    @Override
    public void addSkuInfo(SkuEntity skuEntity) {
        this.save(skuEntity);
    }
    /**
     * 商品详细信息
     */
    @Override
    public ItemVo findInfo(Long skuId) {
        long l = System.currentTimeMillis();
        SkuEntity skuEntity = this.getById(skuId);
        if (null == skuEntity){
            throw new ServiceException("商品不存在");
        }
        ItemVo itemVo = new ItemVo();
        itemVo.setSkuEntity(skuEntity); //商品sku信息
        CompletableFuture<List<SkuImageEntity>> f1 = CompletableFuture.supplyAsync(() -> {
            //sku 图片信息
            List<SkuImageEntity> skuImageEntitieList = skuImageService.list(new QueryWrapper<SkuImageEntity>().lambda()
                    .eq(SkuImageEntity::getSkuId, skuId));
            itemVo.setSkuImageEntities(skuImageEntitieList);
            return skuImageEntitieList;
        });
        CompletableFuture<SpuDescEntity> f2 = CompletableFuture.supplyAsync(() -> {
            //spu商品描述 根据spuId查询描述信息
            SpuDescEntity spuDescEntity = spuDescServcie.getById(skuEntity.getSpuId());
            itemVo.setSpuDescEntity(spuDescEntity);
            return spuDescEntity;
        });
        CompletableFuture<List<AttrVos>> f3 = CompletableFuture.supplyAsync(() -> {
            //TODO sku销售属性
            //根据skuId 得到该sku的属性
            List<AttrVos> bySkuAttList = skuSaleAttrValueMapper.findById(skuId);
            List<AttrVos> collect1 = bySkuAttList.stream().map(attr -> {
                //分割 attrValue
                List<String> collect = Arrays.stream(attr.getAttrValue().split(",")).collect(Collectors.toList());
                attr.setAttrValueList(collect);
                return attr;
            }).collect(Collectors.toList());
            itemVo.setAttrVoList(collect1);
            return collect1;
        });
        CompletableFuture<List<SpuAttrValueEntity>> f4 = CompletableFuture.supplyAsync(() -> {
            //spu 基本属性
            List<SpuAttrValueEntity> spuAttrValueEntityList = spuAttrService.list(new QueryWrapper<SpuAttrValueEntity>().lambda()
                    .eq(SpuAttrValueEntity::getSpuId, skuEntity.getSpuId()));
            itemVo.setSpuAttrValueEntities(spuAttrValueEntityList);
            return spuAttrValueEntityList;
        });
        try {
             CompletableFuture.allOf(f1, f2, f3, f4).get();
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        } catch (ExecutionException e) {
            throw new RuntimeException(e);
        }
//        List vos = new ArrayList<>();
//        voidCompletableFuture.thenAccept(v->{
//            vos.add(f1.join());
//            vos.add(f2.join());
//            vos.add(f3.join());
//            vos.add(f4.join());
//        });
//        voidCompletableFuture.join();
        long l1 = System.currentTimeMillis();
        System.out.println("查询商品信息耗时："+(l1-l));
        //System.out.println("vos:"+vos);
        return itemVo;
    }

    /**
     * 批量导入sku信息
     * @param skuEntities
     */
    @Override
    public void bulkAdd(List<SkuEntity> skuEntities) {
        skuMapper.bulkAllAdd(skuEntities);
    }

    /**
     * 导出sku信息
     * @return
     */
    @Override
    public void export() throws IOException {
        OutputStream outputStream = null;
        try {
            // 记录总数
            Long totalCount = skuMapper.selectCount(null);

            // 每个Sheet存放的数据行数
            Integer sheetDataRows = PER_SHEET_ROW_COUNT;

            // 计算需要的Sheet数量
            Long sheetNum = totalCount % sheetDataRows == 0 ? (totalCount / sheetDataRows) : (totalCount / sheetDataRows + 1);

            // 计算一般情况下每一个Sheet需要写入的次数
            Integer oneSheetWriteCount = sheetDataRows % PER_WRITE_ROW_COUNT == 0 ? (sheetDataRows / PER_WRITE_ROW_COUNT) : (sheetDataRows / PER_WRITE_ROW_COUNT + 1);

            // 计算最后一个sheet需要写入的次数
            Long lastCountAll = totalCount - (sheetNum - 1) * sheetDataRows;
            Long lastSheetWriteCount = lastCountAll % PER_WRITE_ROW_COUNT == 0 ? (lastCountAll / PER_WRITE_ROW_COUNT) : (lastCountAll / PER_WRITE_ROW_COUNT + 1);

            ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
            HttpServletResponse response = requestAttributes.getResponse();
            outputStream = response.getOutputStream();

            // 必须放到循环外，否则会刷新流
            ExcelWriter excelWriter = EasyExcel.write(outputStream).build();

            // 开始分批查询分次写入
            for (int i = 0; i < sheetNum; i++) {
                // 创建Sheet
                WriteSheet sheet = new WriteSheet();
                sheet.setSheetName("测试Sheet1" + i);
                sheet.setSheetNo(i);

                // 循环写入次数
                for (int j = 0; j < (i != sheetNum - 1 ? oneSheetWriteCount : lastSheetWriteCount); j++) {
                    // 分页查询一次20w
                    Page<SkuEntity> page = skuMapper.selectPage(new Page<>(j + 1 + oneSheetWriteCount * i, PER_WRITE_ROW_COUNT), null);
                    List<SkuEntity> empList = page.getRecords();

                    // 封装成可以导出实体类
                    List<SkuEntity> empVoList = new ArrayList<>();
                    for (SkuEntity emp : empList) {
                        SkuEntity empVo = new SkuEntity();
                        BeanUtils.copyProperties(emp, empVo);
                        empVoList.add(empVo);
                    }

                    // 写数据
                    WriteSheet writeSheet = EasyExcel.writerSheet(i, "sku信息" + (i + 1)).head(SkuEntity.class)
                            .registerWriteHandler(new LongestMatchColumnWidthStyleStrategy()).build();
                    excelWriter.write(empVoList, writeSheet);
                }
            }

            // 设置响应头
            response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
            response.setCharacterEncoding("UTF-8");
            String fileName = URLEncoder.encode("sku信息表", String.valueOf(StandardCharsets.UTF_8)).replaceAll("\\+", "%20");
            response.setHeader("Content-disposition", "attachment; filename*=utf-8''" + fileName + ".xlsx");

            // 完成写入
            excelWriter.finish();
            outputStream.flush();
        } catch (IOException | BeansException e) {
            e.printStackTrace();
        } finally {
            if (outputStream != null) {
                outputStream.close();
            }
        }
    }
}

